#ifndef _SELECT_SVR_H_
#define _SELECT_SVR_H_

#include <iostream>
#include <string>

#include <sys/select.h>

#include "Sock.hpp"

using namespace std;

#define BITS 8
#define NUM sizeof(fd_set)*BITS
#define FD_NONE -1

class SelectServer
{
public:
    SelectServer(const uint16_t& port = 8080)
        : _port(port)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        logMessage(DEBUG, "create base socket success");

        // 初始化fd数组，将每个值都设置为无效
        for (int i = 0; i < NUM; i++) _fd_array[i] = FD_NONE;
        // 并且规定数组0号下标就是listensock
        _fd_array[0] = _listensock;
    }
    void Start()
    {
        fd_set rfds; // 读文件描述符集
        while (true)
        {
            // struct timeval timeout = {5, 0};
            // FD_SET(_listensock, &rfds); // 将_listensock添加到文件描述符集
            // int n = select(_listensock + 1, &rfds, nullptr, nullptr, &timeout);
            
            DebugPrint();
            FD_ZERO(&rfds);
            int maxfd = 0;
            for (int i = 0; i < NUM; i++)
            {
                if (_fd_array[i] == FD_NONE) continue;
                FD_SET(_fd_array[i], &rfds);
                if (maxfd < _fd_array[i]) maxfd = _fd_array[i];

            }

            int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);
            switch(n)
            {
            case 0:
                logMessage(DEBUG, "time out...");
                break;
            case -1:
                logMessage(WARNING, "select error: %d : %s", errno, strerror(errno));
                break;
            default:
                // 成功，下面就是调用处理函数
                HandlerEvent(rfds);
                break;
            }
        }
    }

    ~SelectServer()
    {
        if (_listensock >= 0) close(_listensock);
    }
private:
    void HandlerEvent(const fd_set& rfds)
    {
        string clientip;
        uint16_t clientport = 0;
        if (FD_ISSET(_listensock, &rfds))
        {
            // _listensock获取了新的连接
            int sock = Sock::Accept(_listensock, &clientip, &clientport);
            if (sock < 0)
            {
                logMessage(WARNING, "accept error");
                return;
            }
            logMessage(DEBUG, "get a new link success: [%s:%d]: %d", clientip.c_str(), clientport, sock);
            int pos = 0;
            while (_fd_array[pos] != FD_NONE) pos++;
            if (pos == NUM)
            {
                // 说明数组中fd已经满了
                logMessage(WARNING, "%s:%d", "select server already full, close: %d", sock);
                close(sock);
            }
            else
            {
                _fd_array[pos] = sock;
            }
        }
    }
    void DebugPrint()
    {
        cout << "fd_array[]: ";
        for (int i = 0; i < NUM; i++)
        {
            if (_fd_array[i] == FD_NONE) continue;
            cout << _fd_array[i] << " ";
        }
        cout << endl;
    }
private:
    uint16_t _port;
    int _listensock;
    int _fd_array[NUM];
};

#endif 